package com.zhonglz.designPattern.observer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import com.zhonglz.designPattern.observer.listener.EventListener;

import javax.annotation.PostConstruct;
import java.lang.reflect.ParameterizedType;
import java.util.*;

/***
 * 事件发布器，使用静态方法EventBroadcaster.broadcastEvent(..)发布一个事件
 * @author Administrator
 *
 */
@Component
public class EventBroadcaster {
	 private static EventBroadcaster instance;
	 
	 Map<Class<? extends EventObject>, List<EventListener<? extends EventObject>>> map = new HashMap<>();
	 
	 @Autowired
	 private List<EventListener<? extends EventObject>> listeners;
	 
	 
	 @PostConstruct
	    public void init() {
	        instance = this;
	        if (CollectionUtils.isEmpty(listeners)) {
	            return;
	        }
	        for (EventListener<? extends EventObject> listener : listeners) {
	            Class<? extends EventObject> c = getListenEventClass(listener);
	            map.computeIfAbsent(c, key -> new ArrayList<>()).add(listener);
	        }
			// 排序，使用Spring的排序
	        for (List<EventListener<? extends EventObject>> eventListeners : map.values()) {
	            eventListeners.sort(AnnotationAwareOrderComparator.INSTANCE);
	        }

	    }
		// 获取泛型
	    private Class<? extends EventObject> getListenEventClass(EventListener<? extends EventObject> listener) {
	        ParameterizedType  type = (ParameterizedType)listener.getClass().getGenericInterfaces()[0];
	        return (Class<? extends EventObject>) type.getActualTypeArguments()[0];
	    }


	    /**
	     * 发布事件
	     *
	     * @param event
	     */
	    public static void broadcastEvent(EventObject event) {
	        instance.broadcast(event);
	    }


	    private void broadcast(EventObject eventObject) {
	        List<EventListener<? extends EventObject>> eventListeners = map.get(eventObject.getClass());
	        if (eventListeners == null) {
	            //log
	            return;
	        }

	        for (EventListener<? extends EventObject> eventListener : eventListeners) {
	            EventListener<EventObject> listener = (EventListener<EventObject>) eventListener;
	            listener.process(eventObject);
	        }
	    }
}
